import json
import cv2
import time, datetime
from utils import darknet
from utils.tools import rebbox
from utils.config import deviceid, logpath, height_offset, cameras, camerasIdx, result_postIntervalTime, post_baseImage, \
    w_thresh, h_thresh, config_file, data_file, weights, con_times, result_path, threshes, object_detection, sky_thresh, \
    lonlat
from tendo.singleton import SingleInstance
from threading import Thread, Event
from utils.capture import VideoCapture
from utils.tools import utcToBj
from os.path import isdir
from os import mkdir
from utils.logger import Logger

detect_logger = Logger(filename=f'{logpath}/road_detect.log').logger
detect_logger.info("road_detect start!")

try:
    Single = SingleInstance()
except:
    detect_logger.error('road detect process already  exist! ')
    exit()

glon = None
glat = None
gtime = None
events = []
for i in range(len(camerasIdx)):
    events.append(Event())


def dm2d(val):
    val = float(val)
    d = int(val / 100.0)
    m = (val - d * 100) / 60.0
    return d + m


def putText(im, lon, lat, time, pos=(100, 100)):
    if not lonlat:
        return im
    overlay = im.copy()
    x = pos[0]
    y = pos[1]
    c = 255
    if lon:
        lon = dm2d(lon)
        cv2.putText(overlay, "lon: %.6f" % lon, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (c, c, c, 0.8), 3)
    if lat:
        lat = dm2d(lat)
        cv2.putText(overlay, "lat: %.6f" % lat, (x, y + 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (c, c, c, 0.8), 3)
    if time:
        cv2.putText(overlay, time, (x, y + 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (c, c, c, 0.8), 3)
    cv2.addWeighted(overlay, 0.5, im, 0.5, 0, im)
    return im


def mainCap(capId, dict):
    global ftime
    global ftype
    global glon
    global glat
    global gtime
    # capId, main_url = main_camera.split("=")
    main_url = cameras[capId]

    # 调用摄像头
    # capture = VideoCapture("videos/video_result_05.avi")
    capture = VideoCapture(main_url)
    frame_width, frame_height = capture.getsize()
    # frame_cut_width = [frame_width // 5, -frame_width // 5]
    # frame_cut_height = [frame_height // 3, -frame_height // 18]

    if object_detection:
        network, class_names, class_colors = darknet.load_network(
            config_file,
            data_file,
            weights,
            batch_size=1
        )
        width = darknet.network_width(network)
        height = darknet.network_height(network)
        darknet_image = darknet.make_image(width, height, 3)

    watchdog = 0
    inittime = time.time()
    # cv2.namedWindow('live1', cv2.WINDOW_NORMAL)
    while True:
        if len(dict) < 3:
            detect_logger.error("gps data is uninitialized!")
            time.sleep(1)
            continue

        gpsdata = dict[0]
        speed = dict[1]
        gnvtg = dict[2]
        frame = capture.read()
        if frame is None:
            time.sleep(1)
            detect_logger.error("*** Main Cap Has No Frame!")
            # capture = VideoCapture(main_url)
            continue

        frame_show = frame.copy()
        if object_detection:
            # object detection
            # frame_cut = frame[frame_cut_height[0]:frame_cut_height[1], frame_cut_width[0]: frame_cut_width[1], :]
            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            cut_height, cut_width, _ = frame_rgb.shape
            image_resized = cv2.resize(frame_rgb, (width, height), interpolation=cv2.INTER_LINEAR)
            darknet.copy_image_from_bytes(darknet_image, image_resized.tobytes())

            detections = darknet.detect_image(network, class_names, darknet_image, threshes=threshes,
                                              hier_thresh=.5, nms=.15, w_thresh=w_thresh, h_thresh=h_thresh,
                                              sky_thresh=sky_thresh)
            frame_result = frame.copy()
            for label, confidence, bbox in detections:
                left, top, right, bottom = rebbox(bbox, (width, height), (cut_width, cut_height))
                cv2.rectangle(frame_result, (left, top), (right, bottom), (0, 0, 255), 4)
                cv2.putText(frame_result, label, (left, top - 5), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)
                # frame_show[frame_cut_height[0]:frame_cut_height[1], frame_cut_width[0]: frame_cut_width[1], :] = frame_result

            # auto image capture
            if len(detections):
                watchdog += 1
            else:
                watchdog = 0
            if len(detections) and watchdog >= con_times and time.time() - inittime > result_postIntervalTime:
                watchdog = 0
                if gpsdata is None:
                    detect_logger.info("auto capturing failed, no gps info")
                    continue
                detect_logger.info("auto capture ")
                detect_logger.info(f'detected: {detections}')
                inittime = time.time()
                for label, confidence, bbox in detections:
                    left, top, right, bottom = rebbox(bbox, (width, height), (cut_width, cut_height))
                    cv2.rectangle(frame_result, (left, top), (right, bottom), (255, 0, 255), 4)

                # auto capture, save json and images
                ftime = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
                imgSaveDir = f"{result_path}/images/{ftime}"
                if not isdir(imgSaveDir):
                    mkdir(imgSaveDir)
                jsonSaveDir = f"{result_path}/data/"
                if not isdir(jsonSaveDir):
                    mkdir(jsonSaveDir)

                # images
                if post_baseImage:
                    base_frmPath = f"{imgSaveDir}/analyse_{deviceid}_{capId}_01_00_01.jpg"
                else:
                    imgBackupDir = f"{result_path}/backup/images/{ftime}"
                    if not isdir(imgBackupDir):
                        mkdir(imgBackupDir)
                    base_frmPath = f"{imgBackupDir}/analyse_{deviceid}_{capId}_01_00_01.jpg"

                gps = gpsdata.split(",")
                utime = gps[1].split('.')[0]
                ctime = utcToBj(utime)
                lon = gps[4]
                lat = gps[2]
                img = putText(frame, lon, lat, ctime)
                cv2.imwrite(base_frmPath, img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
                detect_logger.info(f"auto save {base_frmPath}")

                img = putText(frame_result, lon, lat, ctime)
                result_frmPath = f"{imgSaveDir}/result_{deviceid}_{capId}_02_10_01.jpg"
                cv2.imwrite(result_frmPath, img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
                detect_logger.info(f"auto save, {result_frmPath}")

                # json
                if gnvtg is None:
                    gnvtg = ''
                resultData = {'ctime': ctime, 'deviceid': deviceid, 'height_offset': height_offset, 'dcway': 0,
                              'imgSaveDir': imgSaveDir, 'detections': json.dumps(detections), 'gpsdata': gpsdata,
                              'speed': speed, 'gpvtg': gnvtg}
                with open(f'{jsonSaveDir}/{ftime}.json', 'w') as f:
                    f.write(json.dumps(resultData))

            frame_show = frame_result.copy()

        # manual image capture
        waitKey = cv2.waitKey(1)
        keys = [' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', 's', 'e', 'r']
        for key in keys:
            if waitKey & 0xFF == ord(key):
                gpsdata = dict[0]
                if gpsdata is None:
                    detect_logger.error("manual capturing failed, no gps info")
                    continue

                if key == ' ':
                    ftype = '00'
                elif key in ['1', '2', '3', '4', '5', '6', '7', '8', '9']:
                    ftype = key.rjust(2, '0')
                elif key in ['s', 'e', 'r']:
                    ftype = key.upper()

                detect_logger.info('manual capture, type: ' + ftype)
                cv2.rectangle(frame_show, (100, 100), (frame_width - 100, frame_height - 100), (0, 255, 0), 4)

                # manualcapture, save json and images
                ftime = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
                imgSaveDir = f"{result_path}/images/{ftime}"
                if not isdir(imgSaveDir):
                    mkdir(imgSaveDir)
                jsonSaveDir = f"{result_path}/data/"
                if not isdir(jsonSaveDir):
                    mkdir(jsonSaveDir)

                gps = gpsdata.split(",")
                utime = gps[1].split('.')[0]
                ctime = utcToBj(utime)
                glon = gps[4]
                glat = gps[2]
                gtime = ctime
                for i in range(1, len(camerasIdx)):
                    events[i].set()

                img = putText(frame, glon, glat, gtime)
                cut_frmPath = f"{imgSaveDir}/analyse_{deviceid}_{capId}_01_{ftype}_00.jpg"
                cv2.imwrite(cut_frmPath, img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
                detect_logger.info(f"manual save {cut_frmPath}")
                if gnvtg is None:
                    gnvtg = ''
                cutJsonData = {'ctime': ctime, 'deviceid': deviceid, 'height_offset': height_offset, 'dcway': 1,
                               'imgSaveDir': imgSaveDir, 'detections': '', 'gpsdata': gpsdata, 'speed': speed,
                               'gpvtg': gnvtg}
                jsonFilePath = f"{jsonSaveDir}/{ftime}.json"
                with open(jsonFilePath, 'w') as f:
                    f.write(json.dumps(cutJsonData))

        # image show
        cv2.namedWindow("live1", cv2.WINDOW_NORMAL)
        cv2.setWindowProperty("live1", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
        # cv2.copyMakeBorder()
        # cv2.resizeWindow("live1", 1920, 1080)
        # cv2.moveWindow("live1", 0, 0)
        # frame_show = cv2.resize(frame_show, (1920-16*15, 1080-9*15))
        cv2.imshow("live1", frame_show)  # 显示
        if cv2.getWindowProperty('live1', 1) < 0:
            detect_logger.info('quit')
            break
    exit()


def subCaps(capId):
    sub_url = cameras[capId]
    eventId = int(camerasIdx.index(capId))
    detect_logger.info(f'sub_camera:{capId}, {eventId}')

    cap = VideoCapture(sub_url)
    while True:
        events[eventId].wait()
        events[eventId].clear()
        # 逐帧捕获
        cut_frame = cap.read()
        if cut_frame is None:
            detect_logger.error("cap failed, capId:%s" % capId)
            continue

        print("=========", glon, glat)
        img = putText(cut_frame, glon, glat, gtime)
        imgSaveDir = f"{result_path}/images/{ftime}"
        cut_frmPath = f"{imgSaveDir}/analyse_{deviceid}_{capId}_01_{ftype}_00.jpg"
        cv2.imwrite(cut_frmPath, img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])

        detect_logger.info(f"manual save {cut_frmPath}")


def detectSever(dict):
    t1 = Thread(target=mainCap, args=(camerasIdx[0], dict))
    t1.start()
    for sub_id in camerasIdx[1:]:
        t = Thread(target=subCaps, args=(sub_id,))
        t.start()


if __name__ == '__main__':
    import multiprocessing

    dict = multiprocessing.Manager().dict()
    dict[0] = 'ww'
    dict[1] = '222'
    dict[2] = '333'

    detectSever(dict)
